Load libraries

library(Seurat)
library(princurve)
library(Revelio)
library(monocle)
library(gprofiler2)
library(seriation)
library(Matrix)
library(dplyr)
library(RColorBrewer)
library(fungible)
library(ggplot2)
library(ggExtra)
library(cowplot)
library(wesanderson)

#Set ggplot theme as classic
theme_set(theme_classic())

Pseudotime in the WT

WT <- readRDS("../QC.filtered.clustered.cells.RDS")

Extract CR and CP neurons

WT$Lineage <- sapply(WT$Cell_ident,
                              FUN = function(x) {
                                if (x %in% c("Cajal-Retzius_neurons", "Hem")) {
                                  x = "Cajal-Retzius_neurons"
                                } else if (x %in% c("Pallial_neurons", "Medial_pallium")) {
                                  x = "Pallial_neurons"
                                } else if(x %in% c("ChP", "ChP_progenitors")) {
                                   x =  "Choroid_Plexus"
                                } else {
                                  x = "other"
                                  }
                              })
Neurons.data <-  subset(WT, idents = c("Cajal-Retzius_neurons", "Pallial_neurons"))

DimPlot(Neurons.data,
        reduction = "spring",
        pt.size = 1,
        cols =  c("#cc391b","#026c9a")
        ) + NoAxes()

rm(WT)

Fit principale curve on the two lineages

Cajal-Retzius cells

Trajectories.Hem <- Neurons.data@meta.data %>%
                    select("Barcodes", "nUMI", "Spring_1", "Spring_2", "AP_signature1","BP_signature1", "EN_signature1", "LN_signature1", "Lineage") %>%
                    filter(Lineage == "Cajal-Retzius_neurons")
fit <- principal_curve(as.matrix(Trajectories.Hem[,c("Spring_1", "Spring_2")]),
                       smoother='lowess',
                       trace=TRUE,
                       f = .7,
                       stretch=0)
## Starting curve---distance^2: 45804778678
## Iteration 1---distance^2: 27732113
## Iteration 2---distance^2: 27728318
#The principal curve smoothed
Hem.pc.line <- as.data.frame(fit$s[order(fit$lambda),]) 

#Pseudotime score
Trajectories.Hem$PseudotimeScore <- fit$lambda/max(fit$lambda)
if (cor(Trajectories.Hem$PseudotimeScore, Neurons.data@assays$SCT@data['Hmga2', Trajectories.Hem$Barcodes]) > 0) {
  Trajectories.Hem$PseudotimeScore <- -(Trajectories.Hem$PseudotimeScore - max(Trajectories.Hem$PseudotimeScore))
}

Pallial neurons

Trajectories.Pallial <- Neurons.data@meta.data %>%
                        select("Barcodes", "nUMI", "Spring_1", "Spring_2", "AP_signature1","BP_signature1", "EN_signature1", "LN_signature1", "Lineage") %>%
                        filter(Lineage == "Pallial_neurons")
fit <- principal_curve(as.matrix(Trajectories.Pallial[,c("Spring_1", "Spring_2")]),
                       smoother='lowess',
                       trace=TRUE,
                       f = .7,
                       stretch=0)
## Starting curve---distance^2: 26984853690
## Iteration 1---distance^2: 22153700
## Iteration 2---distance^2: 22179462
## Iteration 3---distance^2: 22180297
#The principal curve smoothed
Pallial.pc.line <- as.data.frame(fit$s[order(fit$lambda),])

#Pseudotime score
Trajectories.Pallial$PseudotimeScore <- fit$lambda/max(fit$lambda)
if (cor(Trajectories.Pallial$PseudotimeScore, Neurons.data@assays$SCT@data['Hmga2', Trajectories.Pallial$Barcodes]) > 0) {
  Trajectories.Pallial$PseudotimeScore <- -(Trajectories.Pallial$PseudotimeScore - max(Trajectories.Pallial$PseudotimeScore))
}

Combine the two trajectories’ data

Trajectories.neurons.WT <- rbind(Trajectories.Pallial, Trajectories.Hem)
cols <- brewer.pal(n =11, name = "Spectral")

ggplot(Trajectories.neurons.WT, aes(Spring_1, Spring_2)) +
  geom_point(aes(color=PseudotimeScore), size=2, shape=16) + 
  scale_color_gradientn(colours=rev(cols), name='Speudotime score') +
  geom_line(data=Pallial.pc.line, color="#026c9a", size=0.77) +
  geom_line(data=Hem.pc.line, color="#cc391b", size=0.77)

Plot pan-neuronal genes along this axis

Neurons.data <- NormalizeData(Neurons.data, normalization.method = "LogNormalize", scale.factor = 10000, assay = "RNA")
# Neurog2
p1 <- FeaturePlot(object = Neurons.data,
            features = c("Neurog2"),
            pt.size = 0.5,
            cols = c("grey90", brewer.pal(9,"YlGnBu")),
            reduction = "spring",
            order = T) & NoAxes()

Trajectories.neurons.WT$Neurog2 <- Neurons.data@assays$RNA@data["Neurog2", Trajectories.neurons.WT$Barcodes]

p2 <- ggplot(Trajectories.neurons.WT, aes(x= PseudotimeScore, y= Neurog2)) +
        geom_point(aes(color= Lineage), size=0.5) +
        scale_color_manual(values= c("#cc391b", "#026c9a")) +
        geom_smooth(method="loess", n= 50, aes(color= Lineage)) +
        ylim(0,NA)

# Tbr1 
p3 <- FeaturePlot(object = Neurons.data ,
            features = c("Tbr1"),
            pt.size = 0.5,
            cols = c("grey90", brewer.pal(9,"YlGnBu")),
            reduction = "spring",
            order = T) & NoAxes()
Trajectories.neurons.WT$Tbr1 <- Neurons.data@assays$RNA@data["Tbr1", Trajectories.neurons.WT$Barcodes]

p4 <- ggplot(Trajectories.neurons.WT, aes(x= PseudotimeScore, y= Tbr1)) +
        geom_point(aes(color= Lineage), size=0.5) +
        scale_color_manual(values= c("#cc391b", "#026c9a")) +
        geom_smooth(method="loess", n= 50, aes(color= Lineage)) +
        ylim(0,NA)

# Mapt 
p5 <- FeaturePlot(object = Neurons.data ,
            features = c("Mapt"),
            pt.size = 0.5,
            cols = c("grey90", brewer.pal(9,"YlGnBu")),
            reduction = "spring",
            order = T) & NoAxes()

Trajectories.neurons.WT$Mapt <- Neurons.data@assays$RNA@data["Mapt", Trajectories.neurons.WT$Barcodes]

p6 <- ggplot(Trajectories.neurons.WT, aes(x= PseudotimeScore, y= Mapt)) +
        geom_point(aes(color= Lineage), size=0.5) +
        scale_color_manual(values= c("#cc391b", "#026c9a")) +
        geom_smooth(method="loess", n= 50, aes(color= Lineage)) +
        ylim(0,NA)

p1 + p2 + p3 + p4 + p5 + p6 + patchwork::plot_layout(ncol = 2)

Shift Pseudotime in both lineage

Since we observe the first 25% of both trajectories are occupied by few, likely progenitor cells, we shift this cell along the axis

Pseudotime.intervals <- Trajectories.neurons.WT%>%
                          select(Lineage, PseudotimeScore) %>%
                          mutate(Pseudotime.bins = cut(Trajectories.neurons.WT$PseudotimeScore, seq(0, max(Trajectories.neurons.WT$PseudotimeScore) + 0.05, 0.05), dig.lab = 2, right = FALSE)) %>%
                          group_by(Lineage, Pseudotime.bins) %>%
                          summarise(n=n())

ggplot(Pseudotime.intervals, aes(x=Pseudotime.bins, y=n, fill=Lineage)) +
        geom_bar(stat = "identity", width = 0.90) +
        theme(axis.text.x = element_text(angle = 45, hjust=1))+
        scale_fill_manual(values= c("#cc391b", "#026c9a"))

score <- sapply(Trajectories.neurons.WT$PseudotimeScore,
                FUN = function(x) if (x <= 0.2) {x= 0.2} else { x=x })

Trajectories.neurons.WT$PseudotimeScore.shifted <- (score - min(score)) / (max(score) - min(score))
# Neurog2
p1 <- FeaturePlot(object = Neurons.data ,
            features = c("Neurog2"),
            pt.size = 0.5,
            cols = c("grey90", brewer.pal(9,"YlGnBu")),
            reduction = "spring",
            order = T) & NoAxes()

p2 <- ggplot(Trajectories.neurons.WT, aes(x= PseudotimeScore.shifted, y= Neurog2)) +
        geom_point(aes(color= Lineage), size=0.5) +
        scale_color_manual(values= c("#cc391b", "#026c9a")) +
        geom_smooth(method="loess", n= 50, aes(color= Lineage)) +
        ylim(0,NA)

# Tbr1 
p3 <- FeaturePlot(object = Neurons.data ,
            features = c("Tbr1"),
            pt.size = 0.5,
            cols = c("grey90", brewer.pal(9,"YlGnBu")),
            reduction = "spring",
            order = T) & NoAxes()

p4 <- ggplot(Trajectories.neurons.WT, aes(x= PseudotimeScore.shifted, y= Tbr1)) +
        geom_point(aes(color= Lineage), size=0.5) +
        scale_color_manual(values= c("#cc391b", "#026c9a")) +
        geom_smooth(method="loess", n= 50, aes(color= Lineage)) +
        ylim(0,NA)

# Mapt 
p5 <- FeaturePlot(object = Neurons.data ,
            features = c("Mapt"),
            pt.size = 0.5,
            cols = c("grey90", brewer.pal(9,"YlGnBu")),
            reduction = "spring",
            order = T) & NoAxes()

p6 <- ggplot(Trajectories.neurons.WT, aes(x= PseudotimeScore.shifted, y= Mapt)) +
        geom_point(aes(color= Lineage), size=0.5) +
        scale_color_manual(values= c("#cc391b", "#026c9a")) +
        geom_smooth(method="loess", n= 50, aes(color= Lineage)) +
        ylim(0,NA)

p1 + p2 + p3 + p4 + p5 + p6 + patchwork::plot_layout(ncol = 2)

ggplot(Trajectories.neurons.WT, aes(x= PseudotimeScore.shifted, y= nUMI/10000)) +
        geom_point(aes(color= Lineage), size=0.5) +
        scale_color_manual(values= c("#cc391b", "#026c9a")) +
        geom_smooth(method="loess", n= 50, aes(color= Lineage)) +
        ylim(0,NA)

Hem.data <- readRDS("../QC.filtered.clustered.cells.RDS")
Trajectories.neurons.WT$Pseudotime <- Trajectories.neurons.WT$PseudotimeScore.shifted

Neuro.trajectories_WT <- CreateSeuratObject(counts = Hem.data@assays$RNA@data[, Trajectories.neurons.WT$Barcodes],
                                            meta.data = Trajectories.neurons.WT)

spring <- as.matrix(Neuro.trajectories_WT@meta.data %>% select("Spring_1", "Spring_2"))
  
Neuro.trajectories_WT[["spring"]] <- CreateDimReducObject(embeddings = spring, key = "Spring_", assay = DefaultAssay(Neuro.trajectories_WT))
p1 <- FeaturePlot(object = Neuro.trajectories_WT,
            features = "Pseudotime",
            pt.size = 0.5,
            cols = rev(colorRampPalette(brewer.pal(n =11, name = "Spectral"))(100)),
            reduction = "spring",
            order = T) & NoAxes()

p2 <- DimPlot(object = Neuro.trajectories_WT,
        group.by = "Lineage",
        pt.size = 0.5,
        reduction = "spring",
        cols =  c("#cc391b", "#026c9a")) & NoAxes()

p1 + p2

rm(list = ls()[!ls() %in% c("Neuro.trajectories_WT")])

Pseudotime in the KO

KO <- readRDS("./GmncKO.cells.RDS") %>% subset(idents = c(6:9), invert = T)

Compute differentiation states scores

AP

APgenes <- c("Rgcc", "Sparc", "Hes5","Hes1", "Slc1a3",
             "Ddah1", "Ldha", "Hmga2","Sfrp1", "Id4",
             "Creb5", "Ptn", "Lpar1", "Rcn1","Zfp36l1",
             "Sox9", "Sox2", "Nr2e1", "Ttyh1", "Trip6")

KO <- AddModuleScore(KO,
                     features = list(APgenes),
                     name = "AP_signature")

BP

BPgenes <- c("Eomes", "Igsf8", "Insm1", "Elavl2", "Elavl4",
             "Hes6","Gadd45g", "Neurog2", "Btg2", "Neurog1")

KO <- AddModuleScore(KO,
                     features = list(BPgenes),
                     name = "BP_signature")

EN

ENgenes <- c("Mfap4", "Nhlh2", "Nhlh1", "Ppp1r14a", "Nav1",
             "Neurod1", "Sorl1", "Svip", "Cxcl12", "Tenm4",
             "Dll3", "Rgmb", "Cntn2", "Vat1")

KO <- AddModuleScore(KO,
                     features = list(ENgenes),
                     name = "EN_signature")

LN

LNgenes <- c("Snhg11", "Pcsk1n", "Mapt", "Ina", "Stmn4",
             "Gap43", "Tubb2a", "Ly6h","Ptprd", "Mef2c")

KO <- AddModuleScore(KO,
                     features = list(LNgenes),
                     name = "LN_signature")
FeaturePlot(object = KO,
            features = c("AP_signature1", "BP_signature1",
                              "EN_signature1", "LN_signature1"),
            pt.size = 0.75,
            cols = rev(brewer.pal(10,"Spectral")),
            reduction = "spring",
            order = T) & NoAxes() & NoLegend()

Group cells in Pallial or CR lineage

KO$Lineage <- sapply(KO$Cell.ident,
                              FUN = function(x) {
                                if (x %in% c("Neuron_prob.2", "Hem")) {
                                  x = "Cajal-Retzius_neurons"
                                } else if (x %in% c("Neuron_prob.3", "Medial_pallium")) {
                                  x = "Pallial_neurons"
                                } else {
                                  x = "other"
                                  }
                              })
DimPlot(KO,
        reduction = "spring",
        group.by = "Lineage",
        pt.size = 0.5,
        cols =  c("#cc391b","#969696","#026c9a")
        ) + NoAxes()

Fit principale curve on the two lineages

Neurons.data <-  subset(KO,  subset = Lineage %in% c("Cajal-Retzius_neurons", "Pallial_neurons") & Cell.ident %in% c("Neuron_prob.2", "Neuron_prob.3"))

DimPlot(Neurons.data ,
        reduction = "spring",
        group.by = "Lineage",
        pt.size = 1,
        cols =  c("#cc391b","#026c9a")
        ) + NoAxes()

fit <- principal_curve(as.matrix(Neurons.data@meta.data[,c("Spring_1", "Spring_2")]),
                       smoother='lowess',
                       trace=TRUE,
                       f = 1,
                       stretch=0)
## Starting curve---distance^2: 76242448164
## Iteration 1---distance^2: 48308567
## Iteration 2---distance^2: 49237931
## Iteration 3---distance^2: 50119026
## Iteration 4---distance^2: 51105768
## Iteration 5---distance^2: 51819999
## Iteration 6---distance^2: 52369574
## Iteration 7---distance^2: 52732675
## Iteration 8---distance^2: 52936995
## Iteration 9---distance^2: 53060989
## Iteration 10---distance^2: 53117718
#Pseudotime score
PseudotimeScore <- fit$lambda/max(fit$lambda)

if (cor(PseudotimeScore, Neurons.data@assays$SCT@data['Hmga2', ]) > 0) {
  Neurons.data$PseudotimeScore <- -(PseudotimeScore - max(PseudotimeScore))
}

cols <- brewer.pal(n =11, name = "Spectral")

ggplot(Neurons.data@meta.data, aes(Spring_1, Spring_2)) +
  geom_point(aes(color=PseudotimeScore), size=2, shape=16) + 
  scale_color_gradientn(colours=rev(cols), name='Pseudotime score')

Plot pan-neuronal genes along this axis

Neurons.data <- NormalizeData(Neurons.data, normalization.method = "LogNormalize", scale.factor = 10000, assay = "RNA")
Trajectories.neurons <- Neurons.data@meta.data %>% select(Barcodes, Spring_1, Spring_2,
                                                          AP_signature1, BP_signature1, EN_signature1, LN_signature1,
                                                          Lineage, PseudotimeScore)

# Neurog2
p1 <- FeaturePlot(object = Neurons.data,
            features = c("Neurog2"),
            pt.size = 0.5,
            cols = c("grey90", brewer.pal(9,"YlGnBu")),
            reduction = "spring",
            order = T) & NoAxes()

Trajectories.neurons$Neurog2 <- Neurons.data@assays$RNA@data["Neurog2", Trajectories.neurons$Barcodes]

p2 <- ggplot(Trajectories.neurons, aes(x= PseudotimeScore, y= Neurog2)) +
        geom_point(aes(color= Lineage), size=0.5) +
        scale_color_manual(values= c("#cc391b", "#026c9a")) +
        geom_smooth(method="loess", n= 50, aes(color= Lineage)) +
        ylim(0,NA)

# Tbr1 
p3 <- FeaturePlot(object = Neurons.data ,
            features = c("Tbr1"),
            pt.size = 0.5,
            cols = c("grey90", brewer.pal(9,"YlGnBu")),
            reduction = "spring",
            order = T) & NoAxes()
Trajectories.neurons$Tbr1 <- Neurons.data@assays$RNA@data["Tbr1", Trajectories.neurons$Barcodes]

p4 <- ggplot(Trajectories.neurons, aes(x= PseudotimeScore, y= Tbr1)) +
        geom_point(aes(color= Lineage), size=0.5) +
        scale_color_manual(values= c("#cc391b", "#026c9a")) +
        geom_smooth(method="loess", n= 50, aes(color= Lineage)) +
        ylim(0,NA)

# Mapt 
p5 <- FeaturePlot(object = Neurons.data ,
            features = c("Mapt"),
            pt.size = 0.5,
            cols = c("grey90", brewer.pal(9,"YlGnBu")),
            reduction = "spring",
            order = T) & NoAxes()

Trajectories.neurons$Mapt <- Neurons.data@assays$RNA@data["Mapt", Trajectories.neurons$Barcodes]

p6 <- ggplot(Trajectories.neurons, aes(x= PseudotimeScore, y= Mapt)) +
        geom_point(aes(color= Lineage), size=0.5) +
        scale_color_manual(values= c("#cc391b", "#026c9a")) +
        geom_smooth(method="loess", n= 50, aes(color= Lineage)) +
        ylim(0,NA)

p1 + p2 + p3 + p4 + p5 + p6 + patchwork::plot_layout(ncol = 2)

Shift pseudotime score

score <- sapply(Trajectories.neurons$PseudotimeScore,
                FUN = function(x) if (x <= 0.15) {x= 0.15} else { x=x })

Trajectories.neurons$PseudotimeScore.shifted <- (score - min(score)) / (max(score) - min(score))
# Neurog2
p1 <- FeaturePlot(object = Neurons.data ,
            features = c("Neurog2"),
            pt.size = 0.5,
            cols = c("grey90", brewer.pal(9,"YlGnBu")),
            reduction = "spring",
            order = T) & NoAxes()

p2 <- ggplot(Trajectories.neurons, aes(x= PseudotimeScore.shifted, y= Neurog2)) +
        geom_point(aes(color= Lineage), size=0.5) +
        scale_color_manual(values= c("#cc391b", "#026c9a")) +
        geom_smooth(method="loess", n= 50, aes(color= Lineage)) +
        ylim(0,NA)

# Tbr1 
p3 <- FeaturePlot(object = Neurons.data ,
            features = c("Tbr1"),
            pt.size = 0.5,
            cols = c("grey90", brewer.pal(9,"YlGnBu")),
            reduction = "spring",
            order = T) & NoAxes()

p4 <- ggplot(Trajectories.neurons, aes(x= PseudotimeScore.shifted, y= Tbr1)) +
        geom_point(aes(color= Lineage), size=0.5) +
        scale_color_manual(values= c("#cc391b", "#026c9a")) +
        geom_smooth(method="loess", n= 50, aes(color= Lineage)) +
        ylim(0,NA)

# Mapt 
p5 <- FeaturePlot(object = Neurons.data ,
            features = c("Mapt"),
            pt.size = 0.5,
            cols = c("grey90", brewer.pal(9,"YlGnBu")),
            reduction = "spring",
            order = T) & NoAxes()

p6 <- ggplot(Trajectories.neurons, aes(x= PseudotimeScore.shifted, y= Mapt)) +
        geom_point(aes(color= Lineage), size=0.5) +
        scale_color_manual(values= c("#cc391b", "#026c9a")) +
        geom_smooth(method="loess", n= 50, aes(color= Lineage)) +
        ylim(0,NA)

p1 + p2 + p3 + p4 + p5 + p6 + patchwork::plot_layout(ncol = 2)

Trajectories.neurons$nUMI <- Neurons.data$nCount_RNA

ggplot(Trajectories.neurons, aes(x= PseudotimeScore.shifted, y= nUMI/10000)) +
        geom_point(aes(color= Lineage), size=0.5) +
        scale_color_manual(values= c("#cc391b", "#026c9a")) +
        geom_smooth(method="loess", n= 50, aes(color= Lineage)) +
        ylim(0,NA)

Subset the full Seurat object

KO <- readRDS("./GmncKO.cells.RDS") %>% subset(idents = c(6:9), invert = T)
Trajectories.neurons$Pseudotime <- Trajectories.neurons$PseudotimeScore.shifted

Neuro.trajectories_KO <- CreateSeuratObject(counts = KO@assays$RNA@data[, Trajectories.neurons$Barcodes],
                                            meta.data = Trajectories.neurons)

spring <- as.matrix(Neuro.trajectories_KO@meta.data %>% select("Spring_1", "Spring_2"))
  
Neuro.trajectories_KO[["spring"]] <- CreateDimReducObject(embeddings = spring, key = "Spring_", assay = DefaultAssay(Neuro.trajectories_KO))
p1 <- FeaturePlot(object = Neuro.trajectories_KO,
            features = "Pseudotime",
            pt.size = 0.5,
            cols = rev(colorRampPalette(brewer.pal(n =11, name = "Spectral"))(100)),
            reduction = "spring",
            order = T) & NoAxes()

p2 <- DimPlot(object = Neuro.trajectories_KO,
        group.by = "Lineage",
        pt.size = 0.5,
        reduction = "spring",
        cols =  c("#cc391b", "#026c9a")) & NoAxes()

p1 + p2

Cell euclidian distance along pseudotime

rm(list = ls()[!ls() %in% c("Neuro.trajectories_WT","Neuro.trajectories_KO")])
gc()
##            used  (Mb) gc trigger   (Mb)  max used   (Mb)
## Ncells  3515984 187.8    6012948  321.2   6012948  321.2
## Vcells 26894381 205.2  753491556 5748.7 890495468 6794.0

Group cells in 10 bins along pseudotime and average expression by lineage and genotype

TFs <- read.table("TF.csv", sep = ";")[,1]
WT_KO <- merge(x = Neuro.trajectories_WT, y = Neuro.trajectories_KO)

WT_KO <- NormalizeData(WT_KO, normalization.method = "LogNormalize", scale.factor = 10000, assay = "RNA")

WT_KO <-FindVariableFeatures(WT_KO, selection.method = "disp", nfeatures = 3000, assay = "RNA")

WT_KO  <- ScaleData(WT_KO, vars.to.regress = "nCount_RNA", features = TFs)
WT_KO$Genotype <- sapply(WT_KO$orig.ident,
                              FUN = function(x) {
                                if (x %in% c("Hem1", "Hem2")) {
                                  x = "WT"
                                } else {
                                  x = "KO"
                                  }
                              })
nbreaks <- 5
WT_KO$Pseudotime.bins <- cut(WT_KO$Pseudotime, breaks = nbreaks , labels = 1:nbreaks)
# WT Cajal-Retzius
WT_CR <- subset(WT_KO, subset = Genotype == "WT" & Lineage == "Cajal-Retzius_neurons")
  
WT_CR.averages <- AverageExpression(WT_CR,
                                    features = TFs,
                                    group.by = "Pseudotime.bins",
                                    slot = "scale.data")

# KO Cajal-Retzius
KO_CR <- subset(WT_KO, subset = Genotype == "KO" & Lineage == "Cajal-Retzius_neurons")

KO_CR.averages <- AverageExpression(KO_CR,
                                    features = TFs,
                                    group.by = "Pseudotime.bins",
                                    slot = "scale.data")
  
# WT Pallial neurons
WT_Pal <- subset(WT_KO, subset = Genotype == "WT" & Lineage == "Pallial_neurons")

WT_Pal.averages <- AverageExpression(WT_Pal,
                                    features = TFs,
                                    group.by = "Pseudotime.bins",
                                    slot = "scale.data")
  
# KO Pallial neurons  
KO_Pal <- subset(WT_KO, subset = Genotype == "KO" & Lineage == "Pallial_neurons")

KO_Pal.averages <- AverageExpression(KO_Pal,
                                    features = TFs,
                                    group.by = "Pseudotime.bins",
                                    slot = "scale.data")

Compute correlation across conditions

ggplot(WT_CR@meta.data, aes(Spring_1, Spring_2, color= Pseudotime.bins)) + geom_point()

### Distance to KO pallial neurons

Smoothed.point.cor <- pdist::pdist(X= t(WT_CR.averages$RNA),
                                   Y= t(KO_Pal.averages$RNA))

WT_CR.dist <- diag(as.matrix(Smoothed.point.cor))

#
Smoothed.point.cor <- pdist::pdist(X= t(KO_CR.averages$RNA),
                                   Y= t(KO_Pal.averages$RNA))


KO_CR.dist <- diag(as.matrix(Smoothed.point.cor))

#
Smoothed.point.cor <- pdist::pdist(X= t(WT_Pal.averages$RNA),
                                   Y= t(KO_Pal.averages$RNA))

WT_Pal.dist <- diag(as.matrix(Smoothed.point.cor))
data <- data.frame(Distance = c(WT_CR.dist, KO_CR.dist, WT_Pal.dist),
                   Trajectory = rep(c("WT_CR", "KO_CR", "WT_Pal"), each=nbreaks),
                   Pseudotime.bin = factor(rep(paste0("Bin_",1:nbreaks), 3),levels = paste0("Bin_",1:nbreaks)))

ggplot(data, aes(x= Pseudotime.bin, y= Distance, color= Trajectory, group = Trajectory)) +
  geom_line() +
  geom_point() + ggtitle("Distance to KO pallial neurons")

### Distance to WT pallial neurons

Smoothed.point.cor <- pdist::pdist(X= t(WT_CR.averages$RNA),
                                   Y= t(WT_Pal.averages$RNA))

WT_CR.dist <- diag(as.matrix(Smoothed.point.cor))

#
Smoothed.point.cor <- pdist::pdist(X= t(KO_CR.averages$RNA),
                                   Y= t(WT_Pal.averages$RNA))


KO_CR.dist <- diag(as.matrix(Smoothed.point.cor))

#
Smoothed.point.cor <- pdist::pdist(X= t(KO_Pal.averages$RNA),
                                   Y= t(WT_Pal.averages$RNA))

KO_Pal.dist <- diag(as.matrix(Smoothed.point.cor))
data <- data.frame(Distance = c(WT_CR.dist, KO_CR.dist, KO_Pal.dist),
                   Trajectory = rep(c("WT_CR", "KO_CR", "KO_Pal"), each=nbreaks),
                   Pseudotime.bin = factor(rep(paste0("Bin_",1:nbreaks), 3),levels = paste0("Bin_",1:nbreaks)))

ggplot(data, aes(x= Pseudotime.bin, y= Distance, color= Trajectory, group = Trajectory)) +
  geom_line() +
  geom_point() + ggtitle("Distance to WT pallial neurons")

Cosine to KO pallial neurons

Smoothed.point.cor <- cosMat(WT_CR.averages$RNA,
                             KO_Pal.averages$RNA)

WT_CR.dist <- diag(Smoothed.point.cor$cosine)

#
Smoothed.point.cor <- cosMat(KO_CR.averages$RNA,
                             KO_Pal.averages$RNA)


KO_CR.dist <- diag(Smoothed.point.cor$cosine)

#
Smoothed.point.cor <- cosMat(WT_Pal.averages$RNA,
                             KO_Pal.averages$RNA)

KO_Pal.dist <- diag(Smoothed.point.cor$cosine)
data <- data.frame(Distance = c(WT_CR.dist, KO_CR.dist, KO_Pal.dist),
                   Trajectory = rep(c("WT_CR", "KO_CR", "WT_Pal"), each=nbreaks),
                   Pseudotime.bin = factor(rep(paste0("Bin_",1:nbreaks), 3),levels = paste0("Bin_",1:nbreaks)))

ggplot(data, aes(x= Pseudotime.bin, y= Distance, color= Trajectory, group = Trajectory)) +
  geom_line() +
  geom_point() + ggtitle("Distance to KO pallial neurons")

Session Info

#date
format(Sys.time(), "%d %B, %Y, %H,%M")
## [1] "03 juin, 2022, 18,42"
#Packages used
sessionInfo()
## R version 4.2.0 (2022-04-22)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 20.04.4 LTS
## 
## Matrix products: default
## BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
## LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.9.0
## 
## locale:
##  [1] LC_CTYPE=fr_FR.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=fr_FR.UTF-8        LC_COLLATE=fr_FR.UTF-8    
##  [5] LC_MONETARY=fr_FR.UTF-8    LC_MESSAGES=fr_FR.UTF-8   
##  [7] LC_PAPER=fr_FR.UTF-8       LC_NAME=C                 
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
## [11] LC_MEASUREMENT=fr_FR.UTF-8 LC_IDENTIFICATION=C       
## 
## attached base packages:
## [1] splines   stats4    stats     graphics  grDevices utils     datasets 
## [8] methods   base     
## 
## other attached packages:
##  [1] wesanderson_0.3.6   cowplot_1.1.1       ggExtra_0.9        
##  [4] fungible_2.0        RColorBrewer_1.1-2  dplyr_1.0.7        
##  [7] seriation_1.3.1     gprofiler2_0.2.1    monocle_2.22.0     
## [10] DDRTree_0.1.5       irlba_2.3.3         VGAM_1.1-5         
## [13] ggplot2_3.3.5       Biobase_2.54.0      BiocGenerics_0.40.0
## [16] Matrix_1.4-1        Revelio_0.1.0       princurve_2.1.6    
## [19] SeuratObject_4.0.4  Seurat_4.0.5       
## 
## loaded via a namespace (and not attached):
##   [1] plyr_1.8.6            igraph_1.2.11         GPArotation_2014.11-1
##   [4] lazyeval_0.2.2        densityClust_0.3      listenv_0.8.0        
##   [7] scattermore_0.7       fastICA_1.2-3         digest_0.6.29        
##  [10] foreach_1.5.1         htmltools_0.5.2       viridis_0.6.2        
##  [13] fansi_0.5.0           magrittr_2.0.2        tensor_1.5           
##  [16] cluster_2.1.3         ROCR_1.0-11           limma_3.50.0         
##  [19] globals_0.14.0        matrixStats_0.61.0    docopt_0.7.1         
##  [22] spatstat.sparse_2.0-0 pdist_1.2.1           colorspace_2.0-2     
##  [25] ggrepel_0.9.1         xfun_0.28             sparsesvd_0.2        
##  [28] crayon_1.4.2          jsonlite_1.7.2        spatstat.data_2.1-0  
##  [31] survival_3.2-13       zoo_1.8-9             iterators_1.0.13     
##  [34] glue_1.5.1            polyclip_1.10-0       registry_0.5-1       
##  [37] gtable_0.3.0          leiden_0.3.9          future.apply_1.8.1   
##  [40] abind_1.4-5           scales_1.1.1          mvtnorm_1.1-3        
##  [43] pheatmap_1.0.12       DBI_1.1.1             miniUI_0.1.1.1       
##  [46] Rcpp_1.0.8            viridisLite_0.4.0     xtable_1.8-4         
##  [49] clue_0.3-60           reticulate_1.22       spatstat.core_2.3-1  
##  [52] htmlwidgets_1.5.4     httr_1.4.2            FNN_1.1.3            
##  [55] ellipsis_0.3.2        ica_1.0-2             farver_2.1.0         
##  [58] pkgconfig_2.0.3       sass_0.4.0            uwot_0.1.10          
##  [61] deldir_1.0-6          utf8_1.2.2            labeling_0.4.2       
##  [64] tidyselect_1.1.1      rlang_0.4.12          reshape2_1.4.4       
##  [67] later_1.3.0           munsell_0.5.0         tools_4.2.0          
##  [70] generics_0.1.1        ggridges_0.5.3        evaluate_0.14        
##  [73] stringr_1.4.0         fastmap_1.1.0         yaml_2.2.1           
##  [76] goftest_1.2-3         knitr_1.36            fitdistrplus_1.1-6   
##  [79] purrr_0.3.4           RANN_2.6.1            pbapply_1.5-0        
##  [82] future_1.23.0         nlme_3.1-153          mime_0.12            
##  [85] slam_0.1-49           compiler_4.2.0        plotly_4.10.0        
##  [88] png_0.1-7             spatstat.utils_2.2-0  tibble_3.1.6         
##  [91] bslib_0.3.1           stringi_1.7.6         highr_0.9            
##  [94] lattice_0.20-45       HSMMSingleCell_1.14.0 vctrs_0.3.8          
##  [97] pillar_1.6.4          lifecycle_1.0.1       spatstat.geom_2.3-0  
## [100] combinat_0.0-8        lmtest_0.9-39         jquerylib_0.1.4      
## [103] RcppAnnoy_0.0.19      data.table_1.14.2     httpuv_1.6.3         
## [106] patchwork_1.1.1       R6_2.5.1              promises_1.2.0.1     
## [109] TSP_1.1-11            KernSmooth_2.23-20    gridExtra_2.3        
## [112] nleqslv_3.3.2         parallelly_1.29.0     codetools_0.2-18     
## [115] MASS_7.3-57           assertthat_0.2.1      withr_2.4.3          
## [118] qlcMatrix_0.9.7       sctransform_0.3.2     mgcv_1.8-40          
## [121] parallel_4.2.0        grid_4.2.0            rpart_4.1.16         
## [124] Rcsdp_0.1.57.2        tidyr_1.1.4           rmarkdown_2.11       
## [127] Rtsne_0.15            shiny_1.7.1

  1. Institute of Psychiatry and Neuroscience of Paris, INSERM U1266, 75014, Paris, France, ↩︎

LS0tCnRpdGxlOiAiQ29tcGFyaXNvbiBiZXR3ZWVuIHRyYWplY3RvcmllcyBpbiB0aGUgR21uYyBXVC9LTyIKYXV0aG9yOgogICAtIE1hdHRoaWV1IE1vcmVhdV5bSW5zdGl0dXRlIG9mIFBzeWNoaWF0cnkgYW5kIE5ldXJvc2NpZW5jZSBvZiBQYXJpcywgSU5TRVJNIFUxMjY2LCA3NTAxNCwgUGFyaXMsIEZyYW5jZSwgbWF0dGhpZXUubW9yZWF1QGluc2VybS5mcl0gWyFbXShodHRwczovL29yY2lkLm9yZy9zaXRlcy9kZWZhdWx0L2ZpbGVzL2ltYWdlcy9vcmNpZF8xNngxNi5wbmcpXShodHRwczovL29yY2lkLm9yZy8wMDAwLTAwMDItMjU5Mi0yMzczKQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlQiwgJVknKWAiCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDogCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKICAgIGRmX3ByaW50OiB0aWJibGUKICAgIGhpZ2hsaWdodDogaGFkZG9jawogICAgdGhlbWU6IGNvc21vCiAgICBjc3M6ICIuLi9zdHlsZS5jc3MiCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA1CiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogeWVzCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgZmlnLmFsaWduID0gJ2NlbnRlcicsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGNhY2hlLmxhenkgPSBGQUxTRSkKCiMgVG8gdXNlIGJpb21hcnQgCm5ld19jb25maWcgPC0gaHR0cjo6Y29uZmlnKHNzbF92ZXJpZnlwZWVyID0gRkFMU0UpCmh0dHI6OnNldF9jb25maWcobmV3X2NvbmZpZywgb3ZlcnJpZGUgPSBGQUxTRSkKYGBgCgojIExvYWQgbGlicmFyaWVzCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShwcmluY3VydmUpCmxpYnJhcnkoUmV2ZWxpbykKbGlicmFyeShtb25vY2xlKQpsaWJyYXJ5KGdwcm9maWxlcjIpCmxpYnJhcnkoc2VyaWF0aW9uKQpsaWJyYXJ5KE1hdHJpeCkKbGlicmFyeShkcGx5cikKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkoZnVuZ2libGUpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ0V4dHJhKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkod2VzYW5kZXJzb24pCgojU2V0IGdncGxvdCB0aGVtZSBhcyBjbGFzc2ljCnRoZW1lX3NldCh0aGVtZV9jbGFzc2ljKCkpCmBgYAoKIyBQc2V1ZG90aW1lIGluIHRoZSBXVAoKYGBge3J9CldUIDwtIHJlYWRSRFMoIi4uL1FDLmZpbHRlcmVkLmNsdXN0ZXJlZC5jZWxscy5SRFMiKQpgYGAKCiMjIEV4dHJhY3QgQ1IgYW5kIENQIG5ldXJvbnMgCmBgYHtyfQpXVCRMaW5lYWdlIDwtIHNhcHBseShXVCRDZWxsX2lkZW50LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBmdW5jdGlvbih4KSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHggJWluJSBjKCJDYWphbC1SZXR6aXVzX25ldXJvbnMiLCAiSGVtIikpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSAiQ2FqYWwtUmV0eml1c19uZXVyb25zIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoeCAlaW4lIGMoIlBhbGxpYWxfbmV1cm9ucyIsICJNZWRpYWxfcGFsbGl1bSIpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gIlBhbGxpYWxfbmV1cm9ucyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYoeCAlaW4lIGMoIkNoUCIsICJDaFBfcHJvZ2VuaXRvcnMiKSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSAgIkNob3JvaWRfUGxleHVzIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gIm90aGVyIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KQpgYGAKCmBgYHtyfQpOZXVyb25zLmRhdGEgPC0gIHN1YnNldChXVCwgaWRlbnRzID0gYygiQ2FqYWwtUmV0eml1c19uZXVyb25zIiwgIlBhbGxpYWxfbmV1cm9ucyIpKQoKRGltUGxvdChOZXVyb25zLmRhdGEsCiAgICAgICAgcmVkdWN0aW9uID0gInNwcmluZyIsCiAgICAgICAgcHQuc2l6ZSA9IDEsCiAgICAgICAgY29scyA9ICBjKCIjY2MzOTFiIiwiIzAyNmM5YSIpCiAgICAgICAgKSArIE5vQXhlcygpCgpybShXVCkKYGBgCiMjIEZpdCBwcmluY2lwYWxlIGN1cnZlIG9uIHRoZSB0d28gbGluZWFnZXMKCiMjIyBDYWphbC1SZXR6aXVzIGNlbGxzCgpgYGB7cn0KVHJhamVjdG9yaWVzLkhlbSA8LSBOZXVyb25zLmRhdGFAbWV0YS5kYXRhICU+JQogICAgICAgICAgICAgICAgICAgIHNlbGVjdCgiQmFyY29kZXMiLCAiblVNSSIsICJTcHJpbmdfMSIsICJTcHJpbmdfMiIsICJBUF9zaWduYXR1cmUxIiwiQlBfc2lnbmF0dXJlMSIsICJFTl9zaWduYXR1cmUxIiwgIkxOX3NpZ25hdHVyZTEiLCAiTGluZWFnZSIpICU+JQogICAgICAgICAgICAgICAgICAgIGZpbHRlcihMaW5lYWdlID09ICJDYWphbC1SZXR6aXVzX25ldXJvbnMiKQpgYGAKCmBgYHtyfQpmaXQgPC0gcHJpbmNpcGFsX2N1cnZlKGFzLm1hdHJpeChUcmFqZWN0b3JpZXMuSGVtWyxjKCJTcHJpbmdfMSIsICJTcHJpbmdfMiIpXSksCiAgICAgICAgICAgICAgICAgICAgICAgc21vb3RoZXI9J2xvd2VzcycsCiAgICAgICAgICAgICAgICAgICAgICAgdHJhY2U9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgICBmID0gLjcsCiAgICAgICAgICAgICAgICAgICAgICAgc3RyZXRjaD0wKQoKI1RoZSBwcmluY2lwYWwgY3VydmUgc21vb3RoZWQKSGVtLnBjLmxpbmUgPC0gYXMuZGF0YS5mcmFtZShmaXQkc1tvcmRlcihmaXQkbGFtYmRhKSxdKSAKCiNQc2V1ZG90aW1lIHNjb3JlClRyYWplY3Rvcmllcy5IZW0kUHNldWRvdGltZVNjb3JlIDwtIGZpdCRsYW1iZGEvbWF4KGZpdCRsYW1iZGEpCgpgYGAKCmBgYHtyfQppZiAoY29yKFRyYWplY3Rvcmllcy5IZW0kUHNldWRvdGltZVNjb3JlLCBOZXVyb25zLmRhdGFAYXNzYXlzJFNDVEBkYXRhWydIbWdhMicsIFRyYWplY3Rvcmllcy5IZW0kQmFyY29kZXNdKSA+IDApIHsKICBUcmFqZWN0b3JpZXMuSGVtJFBzZXVkb3RpbWVTY29yZSA8LSAtKFRyYWplY3Rvcmllcy5IZW0kUHNldWRvdGltZVNjb3JlIC0gbWF4KFRyYWplY3Rvcmllcy5IZW0kUHNldWRvdGltZVNjb3JlKSkKfQpgYGAKCiMjIyBQYWxsaWFsIG5ldXJvbnMKCmBgYHtyfQpUcmFqZWN0b3JpZXMuUGFsbGlhbCA8LSBOZXVyb25zLmRhdGFAbWV0YS5kYXRhICU+JQogICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoIkJhcmNvZGVzIiwgIm5VTUkiLCAiU3ByaW5nXzEiLCAiU3ByaW5nXzIiLCAiQVBfc2lnbmF0dXJlMSIsIkJQX3NpZ25hdHVyZTEiLCAiRU5fc2lnbmF0dXJlMSIsICJMTl9zaWduYXR1cmUxIiwgIkxpbmVhZ2UiKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKExpbmVhZ2UgPT0gIlBhbGxpYWxfbmV1cm9ucyIpCiAgICAgICAgICAgICAgICAgIApgYGAKCmBgYHtyfQpmaXQgPC0gcHJpbmNpcGFsX2N1cnZlKGFzLm1hdHJpeChUcmFqZWN0b3JpZXMuUGFsbGlhbFssYygiU3ByaW5nXzEiLCAiU3ByaW5nXzIiKV0pLAogICAgICAgICAgICAgICAgICAgICAgIHNtb290aGVyPSdsb3dlc3MnLAogICAgICAgICAgICAgICAgICAgICAgIHRyYWNlPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgZiA9IC43LAogICAgICAgICAgICAgICAgICAgICAgIHN0cmV0Y2g9MCkKCiNUaGUgcHJpbmNpcGFsIGN1cnZlIHNtb290aGVkClBhbGxpYWwucGMubGluZSA8LSBhcy5kYXRhLmZyYW1lKGZpdCRzW29yZGVyKGZpdCRsYW1iZGEpLF0pCgojUHNldWRvdGltZSBzY29yZQpUcmFqZWN0b3JpZXMuUGFsbGlhbCRQc2V1ZG90aW1lU2NvcmUgPC0gZml0JGxhbWJkYS9tYXgoZml0JGxhbWJkYSkKYGBgCgpgYGB7cn0KaWYgKGNvcihUcmFqZWN0b3JpZXMuUGFsbGlhbCRQc2V1ZG90aW1lU2NvcmUsIE5ldXJvbnMuZGF0YUBhc3NheXMkU0NUQGRhdGFbJ0htZ2EyJywgVHJhamVjdG9yaWVzLlBhbGxpYWwkQmFyY29kZXNdKSA+IDApIHsKICBUcmFqZWN0b3JpZXMuUGFsbGlhbCRQc2V1ZG90aW1lU2NvcmUgPC0gLShUcmFqZWN0b3JpZXMuUGFsbGlhbCRQc2V1ZG90aW1lU2NvcmUgLSBtYXgoVHJhamVjdG9yaWVzLlBhbGxpYWwkUHNldWRvdGltZVNjb3JlKSkKfQpgYGAKCiMjIyBDb21iaW5lIHRoZSB0d28gdHJhamVjdG9yaWVzJyBkYXRhCgpgYGB7cn0KVHJhamVjdG9yaWVzLm5ldXJvbnMuV1QgPC0gcmJpbmQoVHJhamVjdG9yaWVzLlBhbGxpYWwsIFRyYWplY3Rvcmllcy5IZW0pCmBgYAoKYGBge3J9CmNvbHMgPC0gYnJld2VyLnBhbChuID0xMSwgbmFtZSA9ICJTcGVjdHJhbCIpCgpnZ3Bsb3QoVHJhamVjdG9yaWVzLm5ldXJvbnMuV1QsIGFlcyhTcHJpbmdfMSwgU3ByaW5nXzIpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3I9UHNldWRvdGltZVNjb3JlKSwgc2l6ZT0yLCBzaGFwZT0xNikgKyAKICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3Vycz1yZXYoY29scyksIG5hbWU9J1NwZXVkb3RpbWUgc2NvcmUnKSArCiAgZ2VvbV9saW5lKGRhdGE9UGFsbGlhbC5wYy5saW5lLCBjb2xvcj0iIzAyNmM5YSIsIHNpemU9MC43NykgKwogIGdlb21fbGluZShkYXRhPUhlbS5wYy5saW5lLCBjb2xvcj0iI2NjMzkxYiIsIHNpemU9MC43NykKYGBgCgojIyMgUGxvdCBwYW4tbmV1cm9uYWwgZ2VuZXMgYWxvbmcgdGhpcyBheGlzCgpgYGB7cn0KTmV1cm9ucy5kYXRhIDwtIE5vcm1hbGl6ZURhdGEoTmV1cm9ucy5kYXRhLCBub3JtYWxpemF0aW9uLm1ldGhvZCA9ICJMb2dOb3JtYWxpemUiLCBzY2FsZS5mYWN0b3IgPSAxMDAwMCwgYXNzYXkgPSAiUk5BIikKYGBgCgpgYGB7ciBmaWcuZGltPWMoOSwxMCl9CiMgTmV1cm9nMgpwMSA8LSBGZWF0dXJlUGxvdChvYmplY3QgPSBOZXVyb25zLmRhdGEsCiAgICAgICAgICAgIGZlYXR1cmVzID0gYygiTmV1cm9nMiIpLAogICAgICAgICAgICBwdC5zaXplID0gMC41LAogICAgICAgICAgICBjb2xzID0gYygiZ3JleTkwIiwgYnJld2VyLnBhbCg5LCJZbEduQnUiKSksCiAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJzcHJpbmciLAogICAgICAgICAgICBvcmRlciA9IFQpICYgTm9BeGVzKCkKClRyYWplY3Rvcmllcy5uZXVyb25zLldUJE5ldXJvZzIgPC0gTmV1cm9ucy5kYXRhQGFzc2F5cyRSTkFAZGF0YVsiTmV1cm9nMiIsIFRyYWplY3Rvcmllcy5uZXVyb25zLldUJEJhcmNvZGVzXQoKcDIgPC0gZ2dwbG90KFRyYWplY3Rvcmllcy5uZXVyb25zLldULCBhZXMoeD0gUHNldWRvdGltZVNjb3JlLCB5PSBOZXVyb2cyKSkgKwogICAgICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yPSBMaW5lYWdlKSwgc2l6ZT0wLjUpICsKICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPSBjKCIjY2MzOTFiIiwgIiMwMjZjOWEiKSkgKwogICAgICAgIGdlb21fc21vb3RoKG1ldGhvZD0ibG9lc3MiLCBuPSA1MCwgYWVzKGNvbG9yPSBMaW5lYWdlKSkgKwogICAgICAgIHlsaW0oMCxOQSkKCiMgVGJyMSAKcDMgPC0gRmVhdHVyZVBsb3Qob2JqZWN0ID0gTmV1cm9ucy5kYXRhICwKICAgICAgICAgICAgZmVhdHVyZXMgPSBjKCJUYnIxIiksCiAgICAgICAgICAgIHB0LnNpemUgPSAwLjUsCiAgICAgICAgICAgIGNvbHMgPSBjKCJncmV5OTAiLCBicmV3ZXIucGFsKDksIllsR25CdSIpKSwKICAgICAgICAgICAgcmVkdWN0aW9uID0gInNwcmluZyIsCiAgICAgICAgICAgIG9yZGVyID0gVCkgJiBOb0F4ZXMoKQpUcmFqZWN0b3JpZXMubmV1cm9ucy5XVCRUYnIxIDwtIE5ldXJvbnMuZGF0YUBhc3NheXMkUk5BQGRhdGFbIlRicjEiLCBUcmFqZWN0b3JpZXMubmV1cm9ucy5XVCRCYXJjb2Rlc10KCnA0IDwtIGdncGxvdChUcmFqZWN0b3JpZXMubmV1cm9ucy5XVCwgYWVzKHg9IFBzZXVkb3RpbWVTY29yZSwgeT0gVGJyMSkpICsKICAgICAgICBnZW9tX3BvaW50KGFlcyhjb2xvcj0gTGluZWFnZSksIHNpemU9MC41KSArCiAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0gYygiI2NjMzkxYiIsICIjMDI2YzlhIikpICsKICAgICAgICBnZW9tX3Ntb290aChtZXRob2Q9ImxvZXNzIiwgbj0gNTAsIGFlcyhjb2xvcj0gTGluZWFnZSkpICsKICAgICAgICB5bGltKDAsTkEpCgojIE1hcHQgCnA1IDwtIEZlYXR1cmVQbG90KG9iamVjdCA9IE5ldXJvbnMuZGF0YSAsCiAgICAgICAgICAgIGZlYXR1cmVzID0gYygiTWFwdCIpLAogICAgICAgICAgICBwdC5zaXplID0gMC41LAogICAgICAgICAgICBjb2xzID0gYygiZ3JleTkwIiwgYnJld2VyLnBhbCg5LCJZbEduQnUiKSksCiAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJzcHJpbmciLAogICAgICAgICAgICBvcmRlciA9IFQpICYgTm9BeGVzKCkKClRyYWplY3Rvcmllcy5uZXVyb25zLldUJE1hcHQgPC0gTmV1cm9ucy5kYXRhQGFzc2F5cyRSTkFAZGF0YVsiTWFwdCIsIFRyYWplY3Rvcmllcy5uZXVyb25zLldUJEJhcmNvZGVzXQoKcDYgPC0gZ2dwbG90KFRyYWplY3Rvcmllcy5uZXVyb25zLldULCBhZXMoeD0gUHNldWRvdGltZVNjb3JlLCB5PSBNYXB0KSkgKwogICAgICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yPSBMaW5lYWdlKSwgc2l6ZT0wLjUpICsKICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPSBjKCIjY2MzOTFiIiwgIiMwMjZjOWEiKSkgKwogICAgICAgIGdlb21fc21vb3RoKG1ldGhvZD0ibG9lc3MiLCBuPSA1MCwgYWVzKGNvbG9yPSBMaW5lYWdlKSkgKwogICAgICAgIHlsaW0oMCxOQSkKCnAxICsgcDIgKyBwMyArIHA0ICsgcDUgKyBwNiArIHBhdGNod29yazo6cGxvdF9sYXlvdXQobmNvbCA9IDIpCmBgYAoKIyMjIFNoaWZ0IFBzZXVkb3RpbWUgaW4gYm90aCBsaW5lYWdlCgpTaW5jZSB3ZSBvYnNlcnZlIHRoZSBmaXJzdCAyNSUgb2YgYm90aCB0cmFqZWN0b3JpZXMgYXJlIG9jY3VwaWVkIGJ5IGZldywgbGlrZWx5IHByb2dlbml0b3IgY2VsbHMsIHdlIHNoaWZ0IHRoaXMgY2VsbCBhbG9uZyB0aGUgYXhpcwoKYGBge3J9ClBzZXVkb3RpbWUuaW50ZXJ2YWxzIDwtIFRyYWplY3Rvcmllcy5uZXVyb25zLldUJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KExpbmVhZ2UsIFBzZXVkb3RpbWVTY29yZSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKFBzZXVkb3RpbWUuYmlucyA9IGN1dChUcmFqZWN0b3JpZXMubmV1cm9ucy5XVCRQc2V1ZG90aW1lU2NvcmUsIHNlcSgwLCBtYXgoVHJhamVjdG9yaWVzLm5ldXJvbnMuV1QkUHNldWRvdGltZVNjb3JlKSArIDAuMDUsIDAuMDUpLCBkaWcubGFiID0gMiwgcmlnaHQgPSBGQUxTRSkpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KExpbmVhZ2UsIFBzZXVkb3RpbWUuYmlucykgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlKG49bigpKQoKZ2dwbG90KFBzZXVkb3RpbWUuaW50ZXJ2YWxzLCBhZXMoeD1Qc2V1ZG90aW1lLmJpbnMsIHk9biwgZmlsbD1MaW5lYWdlKSkgKwogICAgICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDAuOTApICsKICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdD0xKSkrCiAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPSBjKCIjY2MzOTFiIiwgIiMwMjZjOWEiKSkKYGBgCgpgYGB7cn0Kc2NvcmUgPC0gc2FwcGx5KFRyYWplY3Rvcmllcy5uZXVyb25zLldUJFBzZXVkb3RpbWVTY29yZSwKICAgICAgICAgICAgICAgIEZVTiA9IGZ1bmN0aW9uKHgpIGlmICh4IDw9IDAuMikge3g9IDAuMn0gZWxzZSB7IHg9eCB9KQoKVHJhamVjdG9yaWVzLm5ldXJvbnMuV1QkUHNldWRvdGltZVNjb3JlLnNoaWZ0ZWQgPC0gKHNjb3JlIC0gbWluKHNjb3JlKSkgLyAobWF4KHNjb3JlKSAtIG1pbihzY29yZSkpCmBgYAoKYGBge3IgZmlnLmRpbT1jKDksMTApfQojIE5ldXJvZzIKcDEgPC0gRmVhdHVyZVBsb3Qob2JqZWN0ID0gTmV1cm9ucy5kYXRhICwKICAgICAgICAgICAgZmVhdHVyZXMgPSBjKCJOZXVyb2cyIiksCiAgICAgICAgICAgIHB0LnNpemUgPSAwLjUsCiAgICAgICAgICAgIGNvbHMgPSBjKCJncmV5OTAiLCBicmV3ZXIucGFsKDksIllsR25CdSIpKSwKICAgICAgICAgICAgcmVkdWN0aW9uID0gInNwcmluZyIsCiAgICAgICAgICAgIG9yZGVyID0gVCkgJiBOb0F4ZXMoKQoKcDIgPC0gZ2dwbG90KFRyYWplY3Rvcmllcy5uZXVyb25zLldULCBhZXMoeD0gUHNldWRvdGltZVNjb3JlLnNoaWZ0ZWQsIHk9IE5ldXJvZzIpKSArCiAgICAgICAgZ2VvbV9wb2ludChhZXMoY29sb3I9IExpbmVhZ2UpLCBzaXplPTAuNSkgKwogICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9IGMoIiNjYzM5MWIiLCAiIzAyNmM5YSIpKSArCiAgICAgICAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsb2VzcyIsIG49IDUwLCBhZXMoY29sb3I9IExpbmVhZ2UpKSArCiAgICAgICAgeWxpbSgwLE5BKQoKIyBUYnIxIApwMyA8LSBGZWF0dXJlUGxvdChvYmplY3QgPSBOZXVyb25zLmRhdGEgLAogICAgICAgICAgICBmZWF0dXJlcyA9IGMoIlRicjEiKSwKICAgICAgICAgICAgcHQuc2l6ZSA9IDAuNSwKICAgICAgICAgICAgY29scyA9IGMoImdyZXk5MCIsIGJyZXdlci5wYWwoOSwiWWxHbkJ1IikpLAogICAgICAgICAgICByZWR1Y3Rpb24gPSAic3ByaW5nIiwKICAgICAgICAgICAgb3JkZXIgPSBUKSAmIE5vQXhlcygpCgpwNCA8LSBnZ3Bsb3QoVHJhamVjdG9yaWVzLm5ldXJvbnMuV1QsIGFlcyh4PSBQc2V1ZG90aW1lU2NvcmUuc2hpZnRlZCwgeT0gVGJyMSkpICsKICAgICAgICBnZW9tX3BvaW50KGFlcyhjb2xvcj0gTGluZWFnZSksIHNpemU9MC41KSArCiAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0gYygiI2NjMzkxYiIsICIjMDI2YzlhIikpICsKICAgICAgICBnZW9tX3Ntb290aChtZXRob2Q9ImxvZXNzIiwgbj0gNTAsIGFlcyhjb2xvcj0gTGluZWFnZSkpICsKICAgICAgICB5bGltKDAsTkEpCgojIE1hcHQgCnA1IDwtIEZlYXR1cmVQbG90KG9iamVjdCA9IE5ldXJvbnMuZGF0YSAsCiAgICAgICAgICAgIGZlYXR1cmVzID0gYygiTWFwdCIpLAogICAgICAgICAgICBwdC5zaXplID0gMC41LAogICAgICAgICAgICBjb2xzID0gYygiZ3JleTkwIiwgYnJld2VyLnBhbCg5LCJZbEduQnUiKSksCiAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJzcHJpbmciLAogICAgICAgICAgICBvcmRlciA9IFQpICYgTm9BeGVzKCkKCnA2IDwtIGdncGxvdChUcmFqZWN0b3JpZXMubmV1cm9ucy5XVCwgYWVzKHg9IFBzZXVkb3RpbWVTY29yZS5zaGlmdGVkLCB5PSBNYXB0KSkgKwogICAgICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yPSBMaW5lYWdlKSwgc2l6ZT0wLjUpICsKICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPSBjKCIjY2MzOTFiIiwgIiMwMjZjOWEiKSkgKwogICAgICAgIGdlb21fc21vb3RoKG1ldGhvZD0ibG9lc3MiLCBuPSA1MCwgYWVzKGNvbG9yPSBMaW5lYWdlKSkgKwogICAgICAgIHlsaW0oMCxOQSkKCnAxICsgcDIgKyBwMyArIHA0ICsgcDUgKyBwNiArIHBhdGNod29yazo6cGxvdF9sYXlvdXQobmNvbCA9IDIpCmBgYAoKYGBge3J9CmdncGxvdChUcmFqZWN0b3JpZXMubmV1cm9ucy5XVCwgYWVzKHg9IFBzZXVkb3RpbWVTY29yZS5zaGlmdGVkLCB5PSBuVU1JLzEwMDAwKSkgKwogICAgICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yPSBMaW5lYWdlKSwgc2l6ZT0wLjUpICsKICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPSBjKCIjY2MzOTFiIiwgIiMwMjZjOWEiKSkgKwogICAgICAgIGdlb21fc21vb3RoKG1ldGhvZD0ibG9lc3MiLCBuPSA1MCwgYWVzKGNvbG9yPSBMaW5lYWdlKSkgKwogICAgICAgIHlsaW0oMCxOQSkKYGBgCgpgYGB7cn0KSGVtLmRhdGEgPC0gcmVhZFJEUygiLi4vUUMuZmlsdGVyZWQuY2x1c3RlcmVkLmNlbGxzLlJEUyIpCmBgYAoKYGBge3J9ClRyYWplY3Rvcmllcy5uZXVyb25zLldUJFBzZXVkb3RpbWUgPC0gVHJhamVjdG9yaWVzLm5ldXJvbnMuV1QkUHNldWRvdGltZVNjb3JlLnNoaWZ0ZWQKCk5ldXJvLnRyYWplY3Rvcmllc19XVCA8LSBDcmVhdGVTZXVyYXRPYmplY3QoY291bnRzID0gSGVtLmRhdGFAYXNzYXlzJFJOQUBkYXRhWywgVHJhamVjdG9yaWVzLm5ldXJvbnMuV1QkQmFyY29kZXNdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGEuZGF0YSA9IFRyYWplY3Rvcmllcy5uZXVyb25zLldUKQoKc3ByaW5nIDwtIGFzLm1hdHJpeChOZXVyby50cmFqZWN0b3JpZXNfV1RAbWV0YS5kYXRhICU+JSBzZWxlY3QoIlNwcmluZ18xIiwgIlNwcmluZ18yIikpCiAgCk5ldXJvLnRyYWplY3Rvcmllc19XVFtbInNwcmluZyJdXSA8LSBDcmVhdGVEaW1SZWR1Y09iamVjdChlbWJlZGRpbmdzID0gc3ByaW5nLCBrZXkgPSAiU3ByaW5nXyIsIGFzc2F5ID0gRGVmYXVsdEFzc2F5KE5ldXJvLnRyYWplY3Rvcmllc19XVCkpCmBgYAoKYGBge3IgZmlnLmRpbT1jKDYsIDEyKX0KcDEgPC0gRmVhdHVyZVBsb3Qob2JqZWN0ID0gTmV1cm8udHJhamVjdG9yaWVzX1dULAogICAgICAgICAgICBmZWF0dXJlcyA9ICJQc2V1ZG90aW1lIiwKICAgICAgICAgICAgcHQuc2l6ZSA9IDAuNSwKICAgICAgICAgICAgY29scyA9IHJldihjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwobiA9MTEsIG5hbWUgPSAiU3BlY3RyYWwiKSkoMTAwKSksCiAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJzcHJpbmciLAogICAgICAgICAgICBvcmRlciA9IFQpICYgTm9BeGVzKCkKCnAyIDwtIERpbVBsb3Qob2JqZWN0ID0gTmV1cm8udHJhamVjdG9yaWVzX1dULAogICAgICAgIGdyb3VwLmJ5ID0gIkxpbmVhZ2UiLAogICAgICAgIHB0LnNpemUgPSAwLjUsCiAgICAgICAgcmVkdWN0aW9uID0gInNwcmluZyIsCiAgICAgICAgY29scyA9ICBjKCIjY2MzOTFiIiwgIiMwMjZjOWEiKSkgJiBOb0F4ZXMoKQoKcDEgKyBwMgpgYGAKCmBgYHtyfQpybShsaXN0ID0gbHMoKVshbHMoKSAlaW4lIGMoIk5ldXJvLnRyYWplY3Rvcmllc19XVCIpXSkKYGBgCgoKIyBQc2V1ZG90aW1lIGluIHRoZSBLTwoKYGBge3J9CktPIDwtIHJlYWRSRFMoIi4vR21uY0tPLmNlbGxzLlJEUyIpICU+JSBzdWJzZXQoaWRlbnRzID0gYyg2OjkpLCBpbnZlcnQgPSBUKQpgYGAKCiMjIENvbXB1dGUgZGlmZmVyZW50aWF0aW9uIHN0YXRlcyBzY29yZXMKCkFQCgpgYGB7cn0KQVBnZW5lcyA8LSBjKCJSZ2NjIiwgIlNwYXJjIiwgIkhlczUiLCJIZXMxIiwgIlNsYzFhMyIsCiAgICAgICAgICAgICAiRGRhaDEiLCAiTGRoYSIsICJIbWdhMiIsIlNmcnAxIiwgIklkNCIsCiAgICAgICAgICAgICAiQ3JlYjUiLCAiUHRuIiwgIkxwYXIxIiwgIlJjbjEiLCJaZnAzNmwxIiwKICAgICAgICAgICAgICJTb3g5IiwgIlNveDIiLCAiTnIyZTEiLCAiVHR5aDEiLCAiVHJpcDYiKQoKS08gPC0gQWRkTW9kdWxlU2NvcmUoS08sCiAgICAgICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gbGlzdChBUGdlbmVzKSwKICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJBUF9zaWduYXR1cmUiKQpgYGAKCkJQCgpgYGB7cn0KQlBnZW5lcyA8LSBjKCJFb21lcyIsICJJZ3NmOCIsICJJbnNtMSIsICJFbGF2bDIiLCAiRWxhdmw0IiwKICAgICAgICAgICAgICJIZXM2IiwiR2FkZDQ1ZyIsICJOZXVyb2cyIiwgIkJ0ZzIiLCAiTmV1cm9nMSIpCgpLTyA8LSBBZGRNb2R1bGVTY29yZShLTywKICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSBsaXN0KEJQZ2VuZXMpLAogICAgICAgICAgICAgICAgICAgICBuYW1lID0gIkJQX3NpZ25hdHVyZSIpCmBgYAoKRU4KCmBgYHtyfQpFTmdlbmVzIDwtIGMoIk1mYXA0IiwgIk5obGgyIiwgIk5obGgxIiwgIlBwcDFyMTRhIiwgIk5hdjEiLAogICAgICAgICAgICAgIk5ldXJvZDEiLCAiU29ybDEiLCAiU3ZpcCIsICJDeGNsMTIiLCAiVGVubTQiLAogICAgICAgICAgICAgIkRsbDMiLCAiUmdtYiIsICJDbnRuMiIsICJWYXQxIikKCktPIDwtIEFkZE1vZHVsZVNjb3JlKEtPLAogICAgICAgICAgICAgICAgICAgICBmZWF0dXJlcyA9IGxpc3QoRU5nZW5lcyksCiAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiRU5fc2lnbmF0dXJlIikKYGBgCgpMTgoKYGBge3J9CkxOZ2VuZXMgPC0gYygiU25oZzExIiwgIlBjc2sxbiIsICJNYXB0IiwgIkluYSIsICJTdG1uNCIsCiAgICAgICAgICAgICAiR2FwNDMiLCAiVHViYjJhIiwgIkx5NmgiLCJQdHByZCIsICJNZWYyYyIpCgpLTyA8LSBBZGRNb2R1bGVTY29yZShLTywKICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSBsaXN0KExOZ2VuZXMpLAogICAgICAgICAgICAgICAgICAgICBuYW1lID0gIkxOX3NpZ25hdHVyZSIpCmBgYAoKYGBge3J9CkZlYXR1cmVQbG90KG9iamVjdCA9IEtPLAogICAgICAgICAgICBmZWF0dXJlcyA9IGMoIkFQX3NpZ25hdHVyZTEiLCAiQlBfc2lnbmF0dXJlMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJFTl9zaWduYXR1cmUxIiwgIkxOX3NpZ25hdHVyZTEiKSwKICAgICAgICAgICAgcHQuc2l6ZSA9IDAuNzUsCiAgICAgICAgICAgIGNvbHMgPSByZXYoYnJld2VyLnBhbCgxMCwiU3BlY3RyYWwiKSksCiAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJzcHJpbmciLAogICAgICAgICAgICBvcmRlciA9IFQpICYgTm9BeGVzKCkgJiBOb0xlZ2VuZCgpCmBgYAoKIyMgR3JvdXAgY2VsbHMgaW4gUGFsbGlhbCBvciBDUiBsaW5lYWdlCgpgYGB7cn0KS08kTGluZWFnZSA8LSBzYXBwbHkoS08kQ2VsbC5pZGVudCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gZnVuY3Rpb24oeCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh4ICVpbiUgYygiTmV1cm9uX3Byb2IuMiIsICJIZW0iKSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9ICJDYWphbC1SZXR6aXVzX25ldXJvbnMiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmICh4ICVpbiUgYygiTmV1cm9uX3Byb2IuMyIsICJNZWRpYWxfcGFsbGl1bSIpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gIlBhbGxpYWxfbmV1cm9ucyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9ICJvdGhlciIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSkKYGBgCgpgYGB7cn0KRGltUGxvdChLTywKICAgICAgICByZWR1Y3Rpb24gPSAic3ByaW5nIiwKICAgICAgICBncm91cC5ieSA9ICJMaW5lYWdlIiwKICAgICAgICBwdC5zaXplID0gMC41LAogICAgICAgIGNvbHMgPSAgYygiI2NjMzkxYiIsIiM5Njk2OTYiLCIjMDI2YzlhIikKICAgICAgICApICsgTm9BeGVzKCkKYGBgCgojIyBGaXQgcHJpbmNpcGFsZSBjdXJ2ZSBvbiB0aGUgdHdvIGxpbmVhZ2VzCgpgYGB7cn0KTmV1cm9ucy5kYXRhIDwtICBzdWJzZXQoS08sICBzdWJzZXQgPSBMaW5lYWdlICVpbiUgYygiQ2FqYWwtUmV0eml1c19uZXVyb25zIiwgIlBhbGxpYWxfbmV1cm9ucyIpICYgQ2VsbC5pZGVudCAlaW4lIGMoIk5ldXJvbl9wcm9iLjIiLCAiTmV1cm9uX3Byb2IuMyIpKQoKRGltUGxvdChOZXVyb25zLmRhdGEgLAogICAgICAgIHJlZHVjdGlvbiA9ICJzcHJpbmciLAogICAgICAgIGdyb3VwLmJ5ID0gIkxpbmVhZ2UiLAogICAgICAgIHB0LnNpemUgPSAxLAogICAgICAgIGNvbHMgPSAgYygiI2NjMzkxYiIsIiMwMjZjOWEiKQogICAgICAgICkgKyBOb0F4ZXMoKQpgYGAKCmBgYHtyfQpmaXQgPC0gcHJpbmNpcGFsX2N1cnZlKGFzLm1hdHJpeChOZXVyb25zLmRhdGFAbWV0YS5kYXRhWyxjKCJTcHJpbmdfMSIsICJTcHJpbmdfMiIpXSksCiAgICAgICAgICAgICAgICAgICAgICAgc21vb3RoZXI9J2xvd2VzcycsCiAgICAgICAgICAgICAgICAgICAgICAgdHJhY2U9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgICBmID0gMSwKICAgICAgICAgICAgICAgICAgICAgICBzdHJldGNoPTApCmBgYAoKYGBge3J9CiNQc2V1ZG90aW1lIHNjb3JlClBzZXVkb3RpbWVTY29yZSA8LSBmaXQkbGFtYmRhL21heChmaXQkbGFtYmRhKQoKaWYgKGNvcihQc2V1ZG90aW1lU2NvcmUsIE5ldXJvbnMuZGF0YUBhc3NheXMkU0NUQGRhdGFbJ0htZ2EyJywgXSkgPiAwKSB7CiAgTmV1cm9ucy5kYXRhJFBzZXVkb3RpbWVTY29yZSA8LSAtKFBzZXVkb3RpbWVTY29yZSAtIG1heChQc2V1ZG90aW1lU2NvcmUpKQp9Cgpjb2xzIDwtIGJyZXdlci5wYWwobiA9MTEsIG5hbWUgPSAiU3BlY3RyYWwiKQoKZ2dwbG90KE5ldXJvbnMuZGF0YUBtZXRhLmRhdGEsIGFlcyhTcHJpbmdfMSwgU3ByaW5nXzIpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3I9UHNldWRvdGltZVNjb3JlKSwgc2l6ZT0yLCBzaGFwZT0xNikgKyAKICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3Vycz1yZXYoY29scyksIG5hbWU9J1BzZXVkb3RpbWUgc2NvcmUnKQpgYGAKCiMjIyBQbG90IHBhbi1uZXVyb25hbCBnZW5lcyBhbG9uZyB0aGlzIGF4aXMKCmBgYHtyfQpOZXVyb25zLmRhdGEgPC0gTm9ybWFsaXplRGF0YShOZXVyb25zLmRhdGEsIG5vcm1hbGl6YXRpb24ubWV0aG9kID0gIkxvZ05vcm1hbGl6ZSIsIHNjYWxlLmZhY3RvciA9IDEwMDAwLCBhc3NheSA9ICJSTkEiKQpgYGAKCmBgYHtyIGZpZy5kaW09Yyg5LDEwKX0KVHJhamVjdG9yaWVzLm5ldXJvbnMgPC0gTmV1cm9ucy5kYXRhQG1ldGEuZGF0YSAlPiUgc2VsZWN0KEJhcmNvZGVzLCBTcHJpbmdfMSwgU3ByaW5nXzIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBUF9zaWduYXR1cmUxLCBCUF9zaWduYXR1cmUxLCBFTl9zaWduYXR1cmUxLCBMTl9zaWduYXR1cmUxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTGluZWFnZSwgUHNldWRvdGltZVNjb3JlKQoKIyBOZXVyb2cyCnAxIDwtIEZlYXR1cmVQbG90KG9iamVjdCA9IE5ldXJvbnMuZGF0YSwKICAgICAgICAgICAgZmVhdHVyZXMgPSBjKCJOZXVyb2cyIiksCiAgICAgICAgICAgIHB0LnNpemUgPSAwLjUsCiAgICAgICAgICAgIGNvbHMgPSBjKCJncmV5OTAiLCBicmV3ZXIucGFsKDksIllsR25CdSIpKSwKICAgICAgICAgICAgcmVkdWN0aW9uID0gInNwcmluZyIsCiAgICAgICAgICAgIG9yZGVyID0gVCkgJiBOb0F4ZXMoKQoKVHJhamVjdG9yaWVzLm5ldXJvbnMkTmV1cm9nMiA8LSBOZXVyb25zLmRhdGFAYXNzYXlzJFJOQUBkYXRhWyJOZXVyb2cyIiwgVHJhamVjdG9yaWVzLm5ldXJvbnMkQmFyY29kZXNdCgpwMiA8LSBnZ3Bsb3QoVHJhamVjdG9yaWVzLm5ldXJvbnMsIGFlcyh4PSBQc2V1ZG90aW1lU2NvcmUsIHk9IE5ldXJvZzIpKSArCiAgICAgICAgZ2VvbV9wb2ludChhZXMoY29sb3I9IExpbmVhZ2UpLCBzaXplPTAuNSkgKwogICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9IGMoIiNjYzM5MWIiLCAiIzAyNmM5YSIpKSArCiAgICAgICAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsb2VzcyIsIG49IDUwLCBhZXMoY29sb3I9IExpbmVhZ2UpKSArCiAgICAgICAgeWxpbSgwLE5BKQoKIyBUYnIxIApwMyA8LSBGZWF0dXJlUGxvdChvYmplY3QgPSBOZXVyb25zLmRhdGEgLAogICAgICAgICAgICBmZWF0dXJlcyA9IGMoIlRicjEiKSwKICAgICAgICAgICAgcHQuc2l6ZSA9IDAuNSwKICAgICAgICAgICAgY29scyA9IGMoImdyZXk5MCIsIGJyZXdlci5wYWwoOSwiWWxHbkJ1IikpLAogICAgICAgICAgICByZWR1Y3Rpb24gPSAic3ByaW5nIiwKICAgICAgICAgICAgb3JkZXIgPSBUKSAmIE5vQXhlcygpClRyYWplY3Rvcmllcy5uZXVyb25zJFRicjEgPC0gTmV1cm9ucy5kYXRhQGFzc2F5cyRSTkFAZGF0YVsiVGJyMSIsIFRyYWplY3Rvcmllcy5uZXVyb25zJEJhcmNvZGVzXQoKcDQgPC0gZ2dwbG90KFRyYWplY3Rvcmllcy5uZXVyb25zLCBhZXMoeD0gUHNldWRvdGltZVNjb3JlLCB5PSBUYnIxKSkgKwogICAgICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yPSBMaW5lYWdlKSwgc2l6ZT0wLjUpICsKICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPSBjKCIjY2MzOTFiIiwgIiMwMjZjOWEiKSkgKwogICAgICAgIGdlb21fc21vb3RoKG1ldGhvZD0ibG9lc3MiLCBuPSA1MCwgYWVzKGNvbG9yPSBMaW5lYWdlKSkgKwogICAgICAgIHlsaW0oMCxOQSkKCiMgTWFwdCAKcDUgPC0gRmVhdHVyZVBsb3Qob2JqZWN0ID0gTmV1cm9ucy5kYXRhICwKICAgICAgICAgICAgZmVhdHVyZXMgPSBjKCJNYXB0IiksCiAgICAgICAgICAgIHB0LnNpemUgPSAwLjUsCiAgICAgICAgICAgIGNvbHMgPSBjKCJncmV5OTAiLCBicmV3ZXIucGFsKDksIllsR25CdSIpKSwKICAgICAgICAgICAgcmVkdWN0aW9uID0gInNwcmluZyIsCiAgICAgICAgICAgIG9yZGVyID0gVCkgJiBOb0F4ZXMoKQoKVHJhamVjdG9yaWVzLm5ldXJvbnMkTWFwdCA8LSBOZXVyb25zLmRhdGFAYXNzYXlzJFJOQUBkYXRhWyJNYXB0IiwgVHJhamVjdG9yaWVzLm5ldXJvbnMkQmFyY29kZXNdCgpwNiA8LSBnZ3Bsb3QoVHJhamVjdG9yaWVzLm5ldXJvbnMsIGFlcyh4PSBQc2V1ZG90aW1lU2NvcmUsIHk9IE1hcHQpKSArCiAgICAgICAgZ2VvbV9wb2ludChhZXMoY29sb3I9IExpbmVhZ2UpLCBzaXplPTAuNSkgKwogICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9IGMoIiNjYzM5MWIiLCAiIzAyNmM5YSIpKSArCiAgICAgICAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsb2VzcyIsIG49IDUwLCBhZXMoY29sb3I9IExpbmVhZ2UpKSArCiAgICAgICAgeWxpbSgwLE5BKQoKcDEgKyBwMiArIHAzICsgcDQgKyBwNSArIHA2ICsgcGF0Y2h3b3JrOjpwbG90X2xheW91dChuY29sID0gMikKYGBgCgojIyMgU2hpZnQgcHNldWRvdGltZSBzY29yZQoKYGBge3J9CnNjb3JlIDwtIHNhcHBseShUcmFqZWN0b3JpZXMubmV1cm9ucyRQc2V1ZG90aW1lU2NvcmUsCiAgICAgICAgICAgICAgICBGVU4gPSBmdW5jdGlvbih4KSBpZiAoeCA8PSAwLjE1KSB7eD0gMC4xNX0gZWxzZSB7IHg9eCB9KQoKVHJhamVjdG9yaWVzLm5ldXJvbnMkUHNldWRvdGltZVNjb3JlLnNoaWZ0ZWQgPC0gKHNjb3JlIC0gbWluKHNjb3JlKSkgLyAobWF4KHNjb3JlKSAtIG1pbihzY29yZSkpCmBgYAoKYGBge3J9CiMgTmV1cm9nMgpwMSA8LSBGZWF0dXJlUGxvdChvYmplY3QgPSBOZXVyb25zLmRhdGEgLAogICAgICAgICAgICBmZWF0dXJlcyA9IGMoIk5ldXJvZzIiKSwKICAgICAgICAgICAgcHQuc2l6ZSA9IDAuNSwKICAgICAgICAgICAgY29scyA9IGMoImdyZXk5MCIsIGJyZXdlci5wYWwoOSwiWWxHbkJ1IikpLAogICAgICAgICAgICByZWR1Y3Rpb24gPSAic3ByaW5nIiwKICAgICAgICAgICAgb3JkZXIgPSBUKSAmIE5vQXhlcygpCgpwMiA8LSBnZ3Bsb3QoVHJhamVjdG9yaWVzLm5ldXJvbnMsIGFlcyh4PSBQc2V1ZG90aW1lU2NvcmUuc2hpZnRlZCwgeT0gTmV1cm9nMikpICsKICAgICAgICBnZW9tX3BvaW50KGFlcyhjb2xvcj0gTGluZWFnZSksIHNpemU9MC41KSArCiAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0gYygiI2NjMzkxYiIsICIjMDI2YzlhIikpICsKICAgICAgICBnZW9tX3Ntb290aChtZXRob2Q9ImxvZXNzIiwgbj0gNTAsIGFlcyhjb2xvcj0gTGluZWFnZSkpICsKICAgICAgICB5bGltKDAsTkEpCgojIFRicjEgCnAzIDwtIEZlYXR1cmVQbG90KG9iamVjdCA9IE5ldXJvbnMuZGF0YSAsCiAgICAgICAgICAgIGZlYXR1cmVzID0gYygiVGJyMSIpLAogICAgICAgICAgICBwdC5zaXplID0gMC41LAogICAgICAgICAgICBjb2xzID0gYygiZ3JleTkwIiwgYnJld2VyLnBhbCg5LCJZbEduQnUiKSksCiAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJzcHJpbmciLAogICAgICAgICAgICBvcmRlciA9IFQpICYgTm9BeGVzKCkKCnA0IDwtIGdncGxvdChUcmFqZWN0b3JpZXMubmV1cm9ucywgYWVzKHg9IFBzZXVkb3RpbWVTY29yZS5zaGlmdGVkLCB5PSBUYnIxKSkgKwogICAgICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yPSBMaW5lYWdlKSwgc2l6ZT0wLjUpICsKICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPSBjKCIjY2MzOTFiIiwgIiMwMjZjOWEiKSkgKwogICAgICAgIGdlb21fc21vb3RoKG1ldGhvZD0ibG9lc3MiLCBuPSA1MCwgYWVzKGNvbG9yPSBMaW5lYWdlKSkgKwogICAgICAgIHlsaW0oMCxOQSkKCiMgTWFwdCAKcDUgPC0gRmVhdHVyZVBsb3Qob2JqZWN0ID0gTmV1cm9ucy5kYXRhICwKICAgICAgICAgICAgZmVhdHVyZXMgPSBjKCJNYXB0IiksCiAgICAgICAgICAgIHB0LnNpemUgPSAwLjUsCiAgICAgICAgICAgIGNvbHMgPSBjKCJncmV5OTAiLCBicmV3ZXIucGFsKDksIllsR25CdSIpKSwKICAgICAgICAgICAgcmVkdWN0aW9uID0gInNwcmluZyIsCiAgICAgICAgICAgIG9yZGVyID0gVCkgJiBOb0F4ZXMoKQoKcDYgPC0gZ2dwbG90KFRyYWplY3Rvcmllcy5uZXVyb25zLCBhZXMoeD0gUHNldWRvdGltZVNjb3JlLnNoaWZ0ZWQsIHk9IE1hcHQpKSArCiAgICAgICAgZ2VvbV9wb2ludChhZXMoY29sb3I9IExpbmVhZ2UpLCBzaXplPTAuNSkgKwogICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9IGMoIiNjYzM5MWIiLCAiIzAyNmM5YSIpKSArCiAgICAgICAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsb2VzcyIsIG49IDUwLCBhZXMoY29sb3I9IExpbmVhZ2UpKSArCiAgICAgICAgeWxpbSgwLE5BKQoKcDEgKyBwMiArIHAzICsgcDQgKyBwNSArIHA2ICsgcGF0Y2h3b3JrOjpwbG90X2xheW91dChuY29sID0gMikKYGBgCgoKYGBge3J9ClRyYWplY3Rvcmllcy5uZXVyb25zJG5VTUkgPC0gTmV1cm9ucy5kYXRhJG5Db3VudF9STkEKCmdncGxvdChUcmFqZWN0b3JpZXMubmV1cm9ucywgYWVzKHg9IFBzZXVkb3RpbWVTY29yZS5zaGlmdGVkLCB5PSBuVU1JLzEwMDAwKSkgKwogICAgICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yPSBMaW5lYWdlKSwgc2l6ZT0wLjUpICsKICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPSBjKCIjY2MzOTFiIiwgIiMwMjZjOWEiKSkgKwogICAgICAgIGdlb21fc21vb3RoKG1ldGhvZD0ibG9lc3MiLCBuPSA1MCwgYWVzKGNvbG9yPSBMaW5lYWdlKSkgKwogICAgICAgIHlsaW0oMCxOQSkKYGBgCgojIyMgU3Vic2V0IHRoZSBmdWxsIFNldXJhdCBvYmplY3QKCmBgYHtyfQpLTyA8LSByZWFkUkRTKCIuL0dtbmNLTy5jZWxscy5SRFMiKSAlPiUgc3Vic2V0KGlkZW50cyA9IGMoNjo5KSwgaW52ZXJ0ID0gVCkKYGBgCgpgYGB7cn0KVHJhamVjdG9yaWVzLm5ldXJvbnMkUHNldWRvdGltZSA8LSBUcmFqZWN0b3JpZXMubmV1cm9ucyRQc2V1ZG90aW1lU2NvcmUuc2hpZnRlZAoKTmV1cm8udHJhamVjdG9yaWVzX0tPIDwtIENyZWF0ZVNldXJhdE9iamVjdChjb3VudHMgPSBLT0Bhc3NheXMkUk5BQGRhdGFbLCBUcmFqZWN0b3JpZXMubmV1cm9ucyRCYXJjb2Rlc10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0YS5kYXRhID0gVHJhamVjdG9yaWVzLm5ldXJvbnMpCgpzcHJpbmcgPC0gYXMubWF0cml4KE5ldXJvLnRyYWplY3Rvcmllc19LT0BtZXRhLmRhdGEgJT4lIHNlbGVjdCgiU3ByaW5nXzEiLCAiU3ByaW5nXzIiKSkKICAKTmV1cm8udHJhamVjdG9yaWVzX0tPW1sic3ByaW5nIl1dIDwtIENyZWF0ZURpbVJlZHVjT2JqZWN0KGVtYmVkZGluZ3MgPSBzcHJpbmcsIGtleSA9ICJTcHJpbmdfIiwgYXNzYXkgPSBEZWZhdWx0QXNzYXkoTmV1cm8udHJhamVjdG9yaWVzX0tPKSkKYGBgCgpgYGB7cn0KcDEgPC0gRmVhdHVyZVBsb3Qob2JqZWN0ID0gTmV1cm8udHJhamVjdG9yaWVzX0tPLAogICAgICAgICAgICBmZWF0dXJlcyA9ICJQc2V1ZG90aW1lIiwKICAgICAgICAgICAgcHQuc2l6ZSA9IDAuNSwKICAgICAgICAgICAgY29scyA9IHJldihjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwobiA9MTEsIG5hbWUgPSAiU3BlY3RyYWwiKSkoMTAwKSksCiAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJzcHJpbmciLAogICAgICAgICAgICBvcmRlciA9IFQpICYgTm9BeGVzKCkKCnAyIDwtIERpbVBsb3Qob2JqZWN0ID0gTmV1cm8udHJhamVjdG9yaWVzX0tPLAogICAgICAgIGdyb3VwLmJ5ID0gIkxpbmVhZ2UiLAogICAgICAgIHB0LnNpemUgPSAwLjUsCiAgICAgICAgcmVkdWN0aW9uID0gInNwcmluZyIsCiAgICAgICAgY29scyA9ICBjKCIjY2MzOTFiIiwgIiMwMjZjOWEiKSkgJiBOb0F4ZXMoKQoKcDEgKyBwMgpgYGAKCiMgQ2VsbCBldWNsaWRpYW4gZGlzdGFuY2UgYWxvbmcgcHNldWRvdGltZQoKYGBge3J9CnJtKGxpc3QgPSBscygpWyFscygpICVpbiUgYygiTmV1cm8udHJhamVjdG9yaWVzX1dUIiwiTmV1cm8udHJhamVjdG9yaWVzX0tPIildKQpnYygpCmBgYAoKIyMgR3JvdXAgY2VsbHMgaW4gMTAgYmlucyBhbG9uZyBwc2V1ZG90aW1lIGFuZCBhdmVyYWdlIGV4cHJlc3Npb24gYnkgbGluZWFnZSBhbmQgZ2Vub3R5cGUKCmBgYHtyfQpURnMgPC0gcmVhZC50YWJsZSgiVEYuY3N2Iiwgc2VwID0gIjsiKVssMV0KYGBgCgpgYGB7cn0KV1RfS08gPC0gbWVyZ2UoeCA9IE5ldXJvLnRyYWplY3Rvcmllc19XVCwgeSA9IE5ldXJvLnRyYWplY3Rvcmllc19LTykKCldUX0tPIDwtIE5vcm1hbGl6ZURhdGEoV1RfS08sIG5vcm1hbGl6YXRpb24ubWV0aG9kID0gIkxvZ05vcm1hbGl6ZSIsIHNjYWxlLmZhY3RvciA9IDEwMDAwLCBhc3NheSA9ICJSTkEiKQoKV1RfS08gPC1GaW5kVmFyaWFibGVGZWF0dXJlcyhXVF9LTywgc2VsZWN0aW9uLm1ldGhvZCA9ICJkaXNwIiwgbmZlYXR1cmVzID0gMzAwMCwgYXNzYXkgPSAiUk5BIikKCldUX0tPICA8LSBTY2FsZURhdGEoV1RfS08sIHZhcnMudG8ucmVncmVzcyA9ICJuQ291bnRfUk5BIiwgZmVhdHVyZXMgPSBURnMpCmBgYAoKYGBge3J9CldUX0tPJEdlbm90eXBlIDwtIHNhcHBseShXVF9LTyRvcmlnLmlkZW50LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBmdW5jdGlvbih4KSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHggJWluJSBjKCJIZW0xIiwgIkhlbTIiKSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9ICJXVCIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9ICJLTyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSkKbmJyZWFrcyA8LSA1CldUX0tPJFBzZXVkb3RpbWUuYmlucyA8LSBjdXQoV1RfS08kUHNldWRvdGltZSwgYnJlYWtzID0gbmJyZWFrcyAsIGxhYmVscyA9IDE6bmJyZWFrcykKYGBgCgoKYGBge3J9CiMgV1QgQ2FqYWwtUmV0eml1cwpXVF9DUiA8LSBzdWJzZXQoV1RfS08sIHN1YnNldCA9IEdlbm90eXBlID09ICJXVCIgJiBMaW5lYWdlID09ICJDYWphbC1SZXR6aXVzX25ldXJvbnMiKQogIApXVF9DUi5hdmVyYWdlcyA8LSBBdmVyYWdlRXhwcmVzc2lvbihXVF9DUiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSBURnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwLmJ5ID0gIlBzZXVkb3RpbWUuYmlucyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNsb3QgPSAic2NhbGUuZGF0YSIpCgojIEtPIENhamFsLVJldHppdXMKS09fQ1IgPC0gc3Vic2V0KFdUX0tPLCBzdWJzZXQgPSBHZW5vdHlwZSA9PSAiS08iICYgTGluZWFnZSA9PSAiQ2FqYWwtUmV0eml1c19uZXVyb25zIikKCktPX0NSLmF2ZXJhZ2VzIDwtIEF2ZXJhZ2VFeHByZXNzaW9uKEtPX0NSLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmZWF0dXJlcyA9IFRGcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAuYnkgPSAiUHNldWRvdGltZS5iaW5zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2xvdCA9ICJzY2FsZS5kYXRhIikKICAKIyBXVCBQYWxsaWFsIG5ldXJvbnMKV1RfUGFsIDwtIHN1YnNldChXVF9LTywgc3Vic2V0ID0gR2Vub3R5cGUgPT0gIldUIiAmIExpbmVhZ2UgPT0gIlBhbGxpYWxfbmV1cm9ucyIpCgpXVF9QYWwuYXZlcmFnZXMgPC0gQXZlcmFnZUV4cHJlc3Npb24oV1RfUGFsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmZWF0dXJlcyA9IFRGcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAuYnkgPSAiUHNldWRvdGltZS5iaW5zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2xvdCA9ICJzY2FsZS5kYXRhIikKICAKIyBLTyBQYWxsaWFsIG5ldXJvbnMgIApLT19QYWwgPC0gc3Vic2V0KFdUX0tPLCBzdWJzZXQgPSBHZW5vdHlwZSA9PSAiS08iICYgTGluZWFnZSA9PSAiUGFsbGlhbF9uZXVyb25zIikKCktPX1BhbC5hdmVyYWdlcyA8LSBBdmVyYWdlRXhwcmVzc2lvbihLT19QYWwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gVEZzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cC5ieSA9ICJQc2V1ZG90aW1lLmJpbnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzbG90ID0gInNjYWxlLmRhdGEiKQpgYGAKCiMjIENvbXB1dGUgY29ycmVsYXRpb24gYWNyb3NzIGNvbmRpdGlvbnMKCmBgYHtyfQpnZ3Bsb3QoV1RfQ1JAbWV0YS5kYXRhLCBhZXMoU3ByaW5nXzEsIFNwcmluZ18yLCBjb2xvcj0gUHNldWRvdGltZS5iaW5zKSkgKyBnZW9tX3BvaW50KCkKYGBgCiMjIyBEaXN0YW5jZSB0byBLTyBwYWxsaWFsIG5ldXJvbnMKCmBgYHtyfQpTbW9vdGhlZC5wb2ludC5jb3IgPC0gcGRpc3Q6OnBkaXN0KFg9IHQoV1RfQ1IuYXZlcmFnZXMkUk5BKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBZPSB0KEtPX1BhbC5hdmVyYWdlcyRSTkEpKQoKV1RfQ1IuZGlzdCA8LSBkaWFnKGFzLm1hdHJpeChTbW9vdGhlZC5wb2ludC5jb3IpKQoKIwpTbW9vdGhlZC5wb2ludC5jb3IgPC0gcGRpc3Q6OnBkaXN0KFg9IHQoS09fQ1IuYXZlcmFnZXMkUk5BKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBZPSB0KEtPX1BhbC5hdmVyYWdlcyRSTkEpKQoKCktPX0NSLmRpc3QgPC0gZGlhZyhhcy5tYXRyaXgoU21vb3RoZWQucG9pbnQuY29yKSkKCiMKU21vb3RoZWQucG9pbnQuY29yIDwtIHBkaXN0OjpwZGlzdChYPSB0KFdUX1BhbC5hdmVyYWdlcyRSTkEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFk9IHQoS09fUGFsLmF2ZXJhZ2VzJFJOQSkpCgpXVF9QYWwuZGlzdCA8LSBkaWFnKGFzLm1hdHJpeChTbW9vdGhlZC5wb2ludC5jb3IpKQpgYGAKCmBgYHtyfQpkYXRhIDwtIGRhdGEuZnJhbWUoRGlzdGFuY2UgPSBjKFdUX0NSLmRpc3QsIEtPX0NSLmRpc3QsIFdUX1BhbC5kaXN0KSwKICAgICAgICAgICAgICAgICAgIFRyYWplY3RvcnkgPSByZXAoYygiV1RfQ1IiLCAiS09fQ1IiLCAiV1RfUGFsIiksIGVhY2g9bmJyZWFrcyksCiAgICAgICAgICAgICAgICAgICBQc2V1ZG90aW1lLmJpbiA9IGZhY3RvcihyZXAocGFzdGUwKCJCaW5fIiwxOm5icmVha3MpLCAzKSxsZXZlbHMgPSBwYXN0ZTAoIkJpbl8iLDE6bmJyZWFrcykpKQoKZ2dwbG90KGRhdGEsIGFlcyh4PSBQc2V1ZG90aW1lLmJpbiwgeT0gRGlzdGFuY2UsIGNvbG9yPSBUcmFqZWN0b3J5LCBncm91cCA9IFRyYWplY3RvcnkpKSArCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fcG9pbnQoKSArIGdndGl0bGUoIkRpc3RhbmNlIHRvIEtPIHBhbGxpYWwgbmV1cm9ucyIpCgpgYGAKIyMjIERpc3RhbmNlIHRvIFdUIHBhbGxpYWwgbmV1cm9ucwoKYGBge3J9ClNtb290aGVkLnBvaW50LmNvciA8LSBwZGlzdDo6cGRpc3QoWD0gdChXVF9DUi5hdmVyYWdlcyRSTkEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFk9IHQoV1RfUGFsLmF2ZXJhZ2VzJFJOQSkpCgpXVF9DUi5kaXN0IDwtIGRpYWcoYXMubWF0cml4KFNtb290aGVkLnBvaW50LmNvcikpCgojClNtb290aGVkLnBvaW50LmNvciA8LSBwZGlzdDo6cGRpc3QoWD0gdChLT19DUi5hdmVyYWdlcyRSTkEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFk9IHQoV1RfUGFsLmF2ZXJhZ2VzJFJOQSkpCgoKS09fQ1IuZGlzdCA8LSBkaWFnKGFzLm1hdHJpeChTbW9vdGhlZC5wb2ludC5jb3IpKQoKIwpTbW9vdGhlZC5wb2ludC5jb3IgPC0gcGRpc3Q6OnBkaXN0KFg9IHQoS09fUGFsLmF2ZXJhZ2VzJFJOQSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgWT0gdChXVF9QYWwuYXZlcmFnZXMkUk5BKSkKCktPX1BhbC5kaXN0IDwtIGRpYWcoYXMubWF0cml4KFNtb290aGVkLnBvaW50LmNvcikpCmBgYAoKYGBge3J9CmRhdGEgPC0gZGF0YS5mcmFtZShEaXN0YW5jZSA9IGMoV1RfQ1IuZGlzdCwgS09fQ1IuZGlzdCwgS09fUGFsLmRpc3QpLAogICAgICAgICAgICAgICAgICAgVHJhamVjdG9yeSA9IHJlcChjKCJXVF9DUiIsICJLT19DUiIsICJLT19QYWwiKSwgZWFjaD1uYnJlYWtzKSwKICAgICAgICAgICAgICAgICAgIFBzZXVkb3RpbWUuYmluID0gZmFjdG9yKHJlcChwYXN0ZTAoIkJpbl8iLDE6bmJyZWFrcyksIDMpLGxldmVscyA9IHBhc3RlMCgiQmluXyIsMTpuYnJlYWtzKSkpCgpnZ3Bsb3QoZGF0YSwgYWVzKHg9IFBzZXVkb3RpbWUuYmluLCB5PSBEaXN0YW5jZSwgY29sb3I9IFRyYWplY3RvcnksIGdyb3VwID0gVHJhamVjdG9yeSkpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9wb2ludCgpICsgZ2d0aXRsZSgiRGlzdGFuY2UgdG8gV1QgcGFsbGlhbCBuZXVyb25zIikKCmBgYAoKCiMgQ29zaW5lIHRvIEtPIHBhbGxpYWwgbmV1cm9ucwoKYGBge3J9ClNtb290aGVkLnBvaW50LmNvciA8LSBjb3NNYXQoV1RfQ1IuYXZlcmFnZXMkUk5BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIEtPX1BhbC5hdmVyYWdlcyRSTkEpCgpXVF9DUi5kaXN0IDwtIGRpYWcoU21vb3RoZWQucG9pbnQuY29yJGNvc2luZSkKCiMKU21vb3RoZWQucG9pbnQuY29yIDwtIGNvc01hdChLT19DUi5hdmVyYWdlcyRSTkEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgS09fUGFsLmF2ZXJhZ2VzJFJOQSkKCgpLT19DUi5kaXN0IDwtIGRpYWcoU21vb3RoZWQucG9pbnQuY29yJGNvc2luZSkKCiMKU21vb3RoZWQucG9pbnQuY29yIDwtIGNvc01hdChXVF9QYWwuYXZlcmFnZXMkUk5BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIEtPX1BhbC5hdmVyYWdlcyRSTkEpCgpLT19QYWwuZGlzdCA8LSBkaWFnKFNtb290aGVkLnBvaW50LmNvciRjb3NpbmUpCmBgYAoKYGBge3J9CmRhdGEgPC0gZGF0YS5mcmFtZShEaXN0YW5jZSA9IGMoV1RfQ1IuZGlzdCwgS09fQ1IuZGlzdCwgS09fUGFsLmRpc3QpLAogICAgICAgICAgICAgICAgICAgVHJhamVjdG9yeSA9IHJlcChjKCJXVF9DUiIsICJLT19DUiIsICJXVF9QYWwiKSwgZWFjaD1uYnJlYWtzKSwKICAgICAgICAgICAgICAgICAgIFBzZXVkb3RpbWUuYmluID0gZmFjdG9yKHJlcChwYXN0ZTAoIkJpbl8iLDE6bmJyZWFrcyksIDMpLGxldmVscyA9IHBhc3RlMCgiQmluXyIsMTpuYnJlYWtzKSkpCgpnZ3Bsb3QoZGF0YSwgYWVzKHg9IFBzZXVkb3RpbWUuYmluLCB5PSBEaXN0YW5jZSwgY29sb3I9IFRyYWplY3RvcnksIGdyb3VwID0gVHJhamVjdG9yeSkpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9wb2ludCgpICsgZ2d0aXRsZSgiRGlzdGFuY2UgdG8gS08gcGFsbGlhbCBuZXVyb25zIikKCmBgYAoKIyBTZXNzaW9uIEluZm8KCmBgYHtyfQojZGF0ZQpmb3JtYXQoU3lzLnRpbWUoKSwgIiVkICVCLCAlWSwgJUgsJU0iKQoKI1BhY2thZ2VzIHVzZWQKc2Vzc2lvbkluZm8oKQpgYGAKCg==